package project.batch.generic.csv;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Objects;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import batch.util.ParameterUtil;
import project.batch.ProjectBatch;
import project.batch.ProjectPerform;
import project.common.CsvUtil;
import project.common.master.AppConfig;
import common.db.JdbcSource;
import core.config.Factory;
import core.exception.PhysicalException;
import core.file.ZippedLineOutputStream;
import core.util.MojiUtil;

/**
 * 汎用CSV一括出力
 * @author Tadashi Nakayama
 */
public final class ExtractBatch extends ProjectBatch {
	/** ログ出力用クラス */
	private static final Logger LOGGER = LogManager.getLogger(ExtractBatch.class);

	/** Charset */
	private Charset charset = StandardCharsets.UTF_8;

	/**
	 * メイン処理
	 * @param args 引数
	 */
	public static void main(final String... args) {
		int ret = ProjectPerform.start(ExtractBatch.class, args);
		Runtime.getRuntime().exit(ret);
	}

	/**
	 * @see batch.base.Batch#getBatchName()
	 */
	@Override
	public String getBatchName() {
		return "汎用CSV一括出力";
	}

	/**
	 * @see batch.base.Batch#perform(java.lang.String...)
	 */
	@Override
	public int perform(final String... args) {

		Map<String, String[]> params = ParameterUtil.toMap(args);

		if (!ParameterUtil.hasValue("UserPatternId", params)) {
			return RET_ENV_ERROR;
		}

		String[] pattern = params.remove("UserPatternId");

		// ディレクトリ名
		AppConfig ac = Factory.create(AppConfig.class);
		String path = ac.getValue("ExtractBatch", "DIRECTORY", "ZIP");
		if (Objects.toString(path, "").isEmpty() || !new File(path).isDirectory()) {
			return RET_ENV_ERROR;
		}

		File file = null;
		try {
			file = File.createTempFile("ExtractBatch", ".zip", new File(path));

			outputZip(file, pattern[0], params);

			super.addFile(file.getCanonicalPath(), super.getParameter().getJobName() + ".zip");

			return RET_SUCCESS;

		} catch (final IOException ex) {
			if (file != null) {
				file.deleteOnExit();
			}
			LogManager.getLogger().error(ex.getMessage(), ex);
			return RET_ENV_ERROR;
		}
	}

	/**
	 * Zip出力
	 * @param file Zipファイル
	 * @param pattern ユーザパターンID
	 * @param params パラメタ
	 * @throws IOException IO例外
	 */
	private void outputZip(final File file, final String pattern,
					final Map<String, String[]> params) throws IOException {
		try (FileOutputStream fos = new FileOutputStream(file)) {
			try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
				try (ZippedLineOutputStream zlos = new ZippedLineOutputStream(
						bos, MojiUtil.CHARSET_W31J)) {
					Map<String, Object> bind = super.toBindMap(params);
					for (final String ptn : pattern.split(",")) {
						bind.put("Id", ptn);

						ExtractBatchBuilder bd = new ExtractBatchBuilder();
						bd.setParam(bind);
						if (!bd.build()) {
							LOGGER.fatal("パターン取得失敗:[" + bind.get("Id") + "]");
						} else {
							LOGGER.fatal("パターン取得:[" + bd.getNmUserPattern() + "]");

							setOutputInfo(zlos, bd);
							output(zlos, bd, bind);
						}
					}
					zlos.finish();
				}
			}
		}
	}

	/**
	 * 出力情報設定
	 * @param zlos ZippedLineOutputStream
	 * @param bd ExtractBatchBuilder
	 */
	private void setOutputInfo(final ZippedLineOutputStream zlos, final ExtractBatchBuilder bd) {
		if (bd.isBunkatsu()) {
			zlos.setLine(60000);
		} else {
			zlos.setLine(-1);
		}
		zlos.setTitle(CsvUtil.toByteTitle(bd.getTitle(), this.charset));
		zlos.setEntryName(bd.getNmUserPattern() + ".csv");
	}

	/**
	 * 出力処理
	 * @param zlos ZippedLineOutputStream
	 * @param bd ExtractBatchBuilder
	 * @param bind パラメタ
	 */
	private void output(final ZippedLineOutputStream zlos,
					final ExtractBatchBuilder bd, final Map<String, Object> bind) {
		try (Connection conn = JdbcSource.getConnection(bd.getSchema())) {
			conn.setAutoCommit(false);

			int[] index = bd.getPageBreakIndex();
			ExtractBatchQuery query = super.create(ExtractBatchQuery.class);
			if (index.length == 0) {
				query.setOutputStream(zlos);
			} else {
				query.setOutputStream(toCsvPageBreak(zlos, index));
			}
			query.setQuery(bd.getQuery());
			query.setCharset(this.charset);
			query.setTitle(bd.getTitle());
			query.setParam(bind);
			query.execute(conn);

			conn.rollback();
		} catch (final SQLException ex) {
			throw new PhysicalException(ex);
		}
	}

	/**
	 * CsvPageBreakOutputStream化
	 * @param zlos ZippedLineOutputStream
	 * @param index 改頁項目位置
	 * @return CsvPageBreakOutputStream
	 */
	private OutputStream toCsvPageBreak(final ZippedLineOutputStream zlos, final int[] index) {
		return Factory.construct(Factory.getConstructor(
				ZippedLineOutputStream.class, int[].class, Charset.class),
				zlos, index, this.charset);
	}
}
